import { VEFace, VELoop, VEMesh } from "../core/";

export function addFace(struct: VEMesh, loops: VELoop[]) {
  const size = loops.length;
  // if (size < 2) {
  //     console.error('At least 3 loops required to build a face.');
  //     throw new Error("At least 3 loops required to build a face.");
  // }

  // Make some checks before changing topology
  for (let i = 0; i < size; i++) {

    const curr = loops[i];
    const next = loops[(i + 1) % size];

    if (curr.face) {
      console.error('Loop already has a face');
      throw new Error("Loop already has a face");
    }

    if (curr.pair.vertex !== next.vertex) {
      console.error('Loops do not form a chain');
      throw new Error("Loops do not form a chain");
    }
  }

  // Add the face  
  for (let i = 0; i < size; i++) {

    const curr = loops[i];
    const next = loops[(i + 1) % size];

    if (!makeLoopsAdjacent(curr, next)) {
      console.error('Face cannot be created: mesh would be non manifold.');
      throw new Error('Face cannot be created: mesh would be non manifold.');
    }
  }

  const face = new VEFace(loops);
  for (const loop of loops) {
    loop.face = face;
  }

  struct.faces.push(face);
  return face;
}

function makeLoopsAdjacent(
  halfIn: VELoop,
  halfOut: VELoop): boolean {

  if (halfIn.next === halfOut) {
    // Adjacency is alrady correct
    return true;
  }

  // Find a boundary loop different from out.twin and in 
  let g: VELoop | null = null;
  const loop = halfOut.vertex.freeLoopsInLoop(halfOut);
  let he = loop.next();
  while (!g && !he.done) {
    if (he.value !== halfIn) {
      g = he.value;
    }
    he = loop.next();
  }

  if (!g) {
    return false;
  }

  const b = halfIn.next;
  const d = halfOut.prev;
  const h = g.next;

  halfIn.next = halfOut;
  halfOut.prev = halfIn;

  g.next = b;
  b.prev = g;

  d.next = h;
  h.prev = d;

  return true;
}